/**
 * @file ccsds.cc
 *
 * @details
 * CCSDS class provides basic functionality to create binary messages using the CCSDS packet standard.
 *
 * @todo
 */

#include <iostream>
#include <cstring>
#include "ccsds.h"

	/**
	 * CCSDS default constructor.
	 *
	 * This constructor initializes the CCSDS primary and secondary packet headers to default values.
	 *
	 * @param void
	 *
	 */
	Ccsds::Ccsds() {
		std::cout << "CCSDS: CCSDS Constructor called!" << std::endl;

		// Set the packet version number
		ccsdsPacket.ccsdsPriHdr.packet_version_number = VERSION_ONE_CCSDS;

		// Set the default packet type
		ccsdsPacket.ccsdsPriHdr.packet_type = PACKET_TYPE_TELEMETRY;

		// Set the secondary header flag to true (this should be set on for :JETi printers)
		ccsdsPacket.ccsdsPriHdr.secondary_hdr_flag = SECONDARY_HDR_OFF;

		// Set the default APID
		ccsdsPacket.ccsdsPriHdr.apid = APID_GENERIC;

		// Set the default sequence flag (unsegmented data)
		ccsdsPacket.ccsdsPriHdr.sequence_flags = SEQ_NO_SEGMENT;

		// Set the sequence counters to zero
		for (int i=0; i<MAX_APID; i++) {
			apid_pkt_seq_count_table[i] = 0;
		}
		ccsdsPacket.ccsdsPriHdr.packet_sequence_count = apid_pkt_seq_count_table[APID_GENERIC];

		// Set the packet data length to the minimum size defined by the secondary header
		ccsdsPacket.ccsdsPriHdr.packet_data_length = 1;

		// Initialize the message data pointer to NULL
		ccsdsPacket.ccsdsData.data = NULL;
};

	/**
	 * CCSDS destructor.
	 *
	 * @param void
	 *
	 */
	Ccsds::~Ccsds() {
		std::cout << "CCSDS: CCSDS Destructor called!" << std::endl;
		delete [] ccsdsPacket.ccsdsData.data;
	};

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetVersion( void ) {
		return ( ccsdsPacket.ccsdsPriHdr.packet_version_number );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	void Ccsds::CcsdsSetPktType( unsigned short packet_type ) {
		ccsdsPacket.ccsdsPriHdr.packet_type = packet_type;
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetPktType( void ) {
		return ( ccsdsPacket.ccsdsPriHdr.packet_type );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetSecHdrFlag( void ) {
		return ( ccsdsPacket.ccsdsPriHdr.secondary_hdr_flag );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	void Ccsds::CcsdsSetApid( unsigned short apid ) {
		ccsdsPacket.ccsdsPriHdr.apid = apid;
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetApid( void ) {
		return ( ccsdsPacket.ccsdsPriHdr.apid );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetSeqFlags( void ) {
		return ( ccsdsPacket.ccsdsPriHdr.sequence_flags );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	void Ccsds::CcsdsSetSeqCount( unsigned short apid ) {
		ccsdsPacket.ccsdsPriHdr.packet_sequence_count = apid_pkt_seq_count_table[apid]++ % MAX_SEQ_COUNT;
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetSeqCount( unsigned short apid ) {
		 ccsdsPacket.ccsdsPriHdr.packet_sequence_count = apid_pkt_seq_count_table[apid];
		return ( ccsdsPacket.ccsdsPriHdr.packet_sequence_count );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned short Ccsds::CcsdsGetPktLength( void ) {
		return ( ccsdsPacket.ccsdsPriHdr.packet_data_length );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	void Ccsds::CcsdsSetMsgData( char* msg, unsigned int msg_size ) {
		if ( ccsdsPacket.ccsdsData.data != NULL ) {
			delete [] ccsdsPacket.ccsdsData.data;
		}
		ccsdsPacket.ccsdsData.data = new char[msg_size];
		memcpy( ccsdsPacket.ccsdsData.data, msg, msg_size );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	void Ccsds::CcsdsCreatePacket( unsigned short packet_type, unsigned short apid, char* msg, unsigned int msg_size ) {
		CcsdsSetPktType( packet_type );
		CcsdsSetApid( apid );
		CcsdsSetSeqCount( apid );
		CcsdsSetMsgData( msg, msg_size );
		ccsdsPacket.ccsdsPriHdr.packet_data_length = msg_size;
		CcsdsPacketDump();
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	void Ccsds::CcsdsPacketDump( void ) {
		std::cout << "CCSDS: Packet Dump====>" << std::endl;
		std::cout << "CCSDS: Packet Version: " << ccsdsPacket.ccsdsPriHdr.packet_version_number << std::endl;
		std::cout << "CCSDS: Packet Type:    " << ccsdsPacket.ccsdsPriHdr.packet_type << std::endl;
		std::cout << "CCSDS: Sec Hdr Flag:   " << ccsdsPacket.ccsdsPriHdr.secondary_hdr_flag << std::endl;
		std::cout << "CCSDS: APID:           " << ccsdsPacket.ccsdsPriHdr.apid << std::endl;
		std::cout << "CCSDS: Seq Flag:       " << ccsdsPacket.ccsdsPriHdr.sequence_flags << std::endl;
		std::cout << "CCSDS: Pkt Seq Count:  " << ccsdsPacket.ccsdsPriHdr.packet_sequence_count << std::endl;
		std::cout << "CCSDS: Pkt Length:     " << ccsdsPacket.ccsdsPriHdr.packet_data_length << std::endl;

		if ( ccsdsPacket.ccsdsData.data == NULL ) {
			std::cout << "CCSDS: Msg Data:       " << "NO DATA" << std::endl;
		} else {
			std::cout << "CCSDS: Msg Data:       " << ccsdsPacket.ccsdsData.data << std::endl;
		}

		std::cout << "CCSDS: Packet Dump<====" << std::endl;
		std::cout << std::endl;
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	bool Ccsds::CcsdsWrite( char const *msg ) {
		if ( msg == NULL ) {
			return ( false );
		} else {
			return ( true );
		}
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned int  Ccsds::CcsdsSizeof( unsigned char const *msg ) {
		return ( -1 );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned int  Ccsds::CcsdsHashCalc( unsigned char const *msg ) {
		return ( -1 );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned int  Ccsds::CcsdsHashWrite( unsigned char const *msg ) {
		return ( -1 );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	unsigned int  Ccsds::CcsdsHashRead( unsigned char const *msg ) {
		return ( -1 );
	}

	/**
	 * CCSDS
	 *
	 * @param void
	 *
	 */
	bool Ccsds::CcsdsHashCompare( unsigned char const *msg1, unsigned char const *msg2 ) {
		return ( false );
	}

